<template>
  <div class="user-avatar-layout">
    <div class="user-info-head" @click="editCropper" title="点击上传头像">
      <el-avatar :size="size" :src="avatarUrl">
        <el-icon><Plus /></el-icon>
      </el-avatar>
    </div>
    <el-dialog title="修改头像" v-model="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
      <el-row>
        <el-col :xs="24" :md="12" :style="{ height: '350px' }">
          <vue-cropper
            ref="cropper"
            :img="options.img"
            :info="true"
            :autoCrop="options.autoCrop"
            :autoCropWidth="cropWidth"
            :autoCropHeight="cropHeight"
            :fixedBox="options.fixedBox"
            :outputType="outputType"
            @realTime="realTime"
            v-if="visible"
          />
        </el-col>
        <el-col :xs="24" :md="12" :style="{ height: '350px' }">
          <div class="avatar-upload-preview">
            <img :src="previews.url" :style="previews.img" />
          </div>
        </el-col>
      </el-row>
      <br />
      <el-row>
        <el-col :lg="2" :sm="3" :xs="3">
          <el-upload action="#" :show-file-list="false" :before-upload="beforeUpload">
            <el-button>
              <span>选择</span><el-icon><UploadFilled /></el-icon>
            </el-button>
          </el-upload>
        </el-col>
        <el-col :lg="{ span: 1, offset: 2 }" :sm="2" :xs="2">
          <el-button icon="Plus" @click="changeScale(1)"></el-button>
        </el-col>
        <el-col :lg="{ span: 1, offset: 1 }" :sm="2" :xs="2">
          <el-button icon="Minus" @click="changeScale(-1)"></el-button>
        </el-col>
        <el-col :lg="{ span: 1, offset: 1 }" :sm="2" :xs="2">
          <el-button icon="RefreshLeft" @click="rotateLeft"></el-button>
        </el-col>
        <el-col :lg="{ span: 1, offset: 1 }" :sm="2" :xs="2">
          <el-button icon="RefreshRight" @click="rotateRight"></el-button>
        </el-col>
        <el-col :lg="{ span: 2, offset: 6 }" :sm="2" :xs="2">
          <el-button type="primary" @click="uploadImg" :disabled="isSubmit" :loading="isLoading">提 交</el-button>
        </el-col>
      </el-row>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { computed, reactive, ref } from "vue";
import { editUserProfileAvatarApi } from "@/api";
import { debounce, fileToBase64 } from "@/utils";
import { ElMessage } from "element-plus";
import { FILE_PREFIX } from "@/config";
import { getEnv } from "@/utils/getEnv";
import { useUserStore } from "@/stores";
import defAva from "@/assets/images/avatar.jpg";
import "vue-cropper/dist/index.css";

defineOptions({
  name: "UserAvatar"
});
interface Props {
  img?: string;
  size?: number;
  cropWidth?: number;
  cropHeight?: number;
  outputType?: "jpeg" | "png" | "jpg" | "webp";
  isBase?: boolean;
  upload?: (formData: FormData | string) => Promise<void> | void;
}
const props = withDefaults(defineProps<Props>(), {
  img: "",
  size: 148,
  cropWidth: 200,
  cropHeight: 200,
  outputType: "jpg",
  isBase: false
});
const emits = defineEmits(["updataUser"]);
const open = ref<boolean>(false);
const visible = ref<boolean>(false);
const cropper = ref();
const resizeHandler = ref<any>(null);
const isSubmit = ref<boolean>(true);
const isLoading = ref<boolean>(false);
const avatarUrl = computed(() => (props.img && props.img ? getEnv("VITE_PROXY") + props.img : defAva));
const useUser = useUserStore();
const options = reactive({
  img: "",
  autoCrop: true, // 是否默认生成截图框
  fixedBox: true // 固定截图框大小 不允许改变
});
const previews = reactive({
  url: "",
  img: {}
});

/**
 * @description 编辑头像弹窗
 */
const editCropper = () => {
  open.value = true;
};

/**
 * @description 打开弹出层结束时的回调
 */
const modalOpened = () => {
  visible.value = true;
  if (!resizeHandler.value) {
    resizeHandler.value = debounce(() => {
      cropper.value && cropper.value.refresh();
    }, 100);
  }
  window.addEventListener("resize", resizeHandler.value);
};

/**
 * @description 向左旋转
 */
const rotateLeft = () => {
  cropper.value && cropper.value.rotateLeft();
  isSubmit.value = false;
};

/**
 * @description 向右旋转
 */
const rotateRight = () => {
  cropper.value && cropper.value.rotateRight();
  isSubmit.value = false;
};

/**
 * @description 图片缩放
 */
const changeScale = (num: number) => {
  num = num || 1;
  cropper.value && cropper.value.changeScale(num);
  isSubmit.value = false;
};

/**
 * @description 上传预处理
 * @param file 文件
 */
const beforeUpload = (file: Blob) => {
  if (file.type.indexOf("image/") == -1) {
    ElMessage.error("请上传以JPG,PNG等为后缀的图片");
    return false;
  }
  const size = file.size / 1024 / 1024 < 10;
  if (!size) {
    ElMessage.error("图片大小不能超过10MB");
    return false;
  }
  const reader = new FileReader();
  reader.readAsDataURL(file);
  reader.onload = () => {
    options.img = reader.result as string;
  };
  isSubmit.value = false;
  return false;
};

/**
 * @description 上传图片
 */
const uploadImg = () => {
  if (!cropper.value) return;
  cropper.value.getCropBlob(async (data: any) => {
    const formData = new FormData();
    formData.append("avatarfile", data, FILE_PREFIX);
    const res = await editUserProfileAvatarApi(formData);
    if (res.code !== 200) {
      return ElMessage.error(res.message);
    }
    useUser.userInfo.avatar = res.data;
    ElMessage.success("上传成功");
    isSubmit.value = true;
    isLoading.value = true;
    emits("updataUser");
    try {
      if (!props.upload) {
        console.warn("The upload method cannot be empty!!!");
        return;
      }
      if (props.isBase) {
        const file = formData.get(FILE_PREFIX) as File;
        const result = await fileToBase64(file);
        props.upload(result);
      } else {
        props.upload(formData);
      }
    } catch (error) {
      console.log(error);
    } finally {
      options.img = "";
      isLoading.value = false;
      open.value = false;
    }
  });
};

/**
 * @description 实时预览
 * @param data 数据
 */
const realTime = (data: any) => {
  Object.assign(previews, data);
};

/**
 * @description 关闭窗口
 */
const closeDialog = () => {
  visible.value = false;
  isSubmit.value = true;
  window.removeEventListener("resize", resizeHandler.value);
};

defineExpose({
  open
});
</script>

<style scoped lang="scss">
.user-avatar-layout {
  .user-info-head {
    position: relative;
    display: inline-block;
    .el-avatar--circle {
      border-radius: 4px;
    }
  }
  .user-info-head:hover:after {
    content: "+";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    color: #eee;
    background: rgba(0, 0, 0, 0.5);
    font-size: 24px;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    cursor: pointer;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}
</style>
